/* eslint no-useless-escape:0 import/prefer-default-export:0 */
import {v4 as uuidV4} from 'uuid';
import _, {curry, filter, find, flattenDeep, get, map, omit, pad} from 'lodash';
import Nzh from 'nzh';
import Big from 'big.js'

const _map = curry(map);
const _get = curry(get);
const _filter = curry(filter);

const reg =
  /(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/;

export const isUrl = (path: string): boolean => reg.test(path);

export const isAntDesignPro = (): boolean => {
  if (ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site') {
    return true;
  }
  return window.location.hostname === 'preview.pro.ant.design';
};

// 给官方演示站点用，用于关闭真实开发环境不需要使用的特性
export const isAntDesignProOrDev = (): boolean => {
  const {NODE_ENV} = process.env;
  if (NODE_ENV === 'development') {
    return true;
  }
  return isAntDesignPro();
};

export const getCascaderValue = (id: string | number, treeData: any[]): (string | number)[] => {
  const arr: (string | number)[] = [id];
  const getParent = (childId: string | number, children: any[]) => {
    if (Array.isArray(children)) {
      children.forEach((item) => {
        if (Array.isArray(item.children) && item.children.find((child) => child.key === childId)) {
          arr.unshift(item.key);
          getParent(item.key, treeData);
        } else {
          getParent(childId, item.children);
        }
      });
    }
  };
  getParent(id, treeData);
  return arr;
};

export function newGuid() {
  let guid = '';
  for (let i = 1; i <= 32; i += 1) {
    const n = Math.floor(Math.random() * 16.0).toString(16);
    guid += n;
    if (i === 8 || i === 12 || i === 16 || i === 20) guid += '-';
  }
  return guid;
}

const USE_MOCK = false;

export const wait = () => new Promise((resolve, reject) => setTimeout(resolve, 1000));

// 千分位
export const thousandsRender = (text: any) => {
  if (!isNaN(text)) {
    const result = Number(Number(text).toFixed(2)).toLocaleString() // 不能处理小数位尾部为0的情况
    const [int, float = ''] = result.split('.')
    return `${int}.${pad(float, 2, '0')}`; // 如果小数位尾部有0，则补足
  }
  return text;
};

// 扁平化
export const getDeepArr = (arr: any) =>
  arr?.reduce((acc: any, i: any) => {
    if (i.child && i.child.length) return [...acc, getDeepArr(i.child)];
    return [...acc, i];
  }, []);

// 数字转中文文字，审批流弹窗用
export const sectionToChinese = (num) => {
  if (!/^\d*(\.\d*)?$/.test(num)) {
    alert('Number is wrong!');
    return 'Number is wrong!';
  }
  var AA = new Array('零', '一', '二', '三', '四', '五', '六', '七', '八', '九');
  var BB = new Array('', '十', '百', '千', '万', '亿', '点', '');
  var a = ('' + num).replace(/(^0*)/g, '').split('.'),
    k = 0,
    re = '';
  for (var i = a[0].length - 1; i >= 0; i--) {
    switch (k) {
      case 0:
        re = BB[7] + re;
        break;
      case 4:
        if (!new RegExp('0{4}\\d{' + (a[0].length - i - 1) + '}$').test(a[0])) re = BB[4] + re;
        break;
      case 8:
        re = BB[5] + re;
        BB[7] = BB[5];
        k = 0;
        break;
    }
    if (k % 4 == 2 && a[0].charAt(i + 2) != 0 && a[0].charAt(i + 1) == 0) re = AA[0] + re;
    if (a[0].charAt(i) != 0) re = AA[a[0].charAt(i)] + BB[k % 4] + re;
    k++;
  }
  if (a.length > 1) {
    //加上小数部分(如果有小数部分)
    re += BB[6];
    for (var i = 0; i < a[1].length; i++) re += AA[a[1].charAt(i)];
  }
  return re;
};

// 将标准option格式转为valueEnum
export const resolveValueEnum = (data) =>
  data.reduce((acc, item) => {
    return {
      ...acc,
      [item.value]: item.label,
    };
  }, {});

// user接口部门列表转valueEnum格式
export const resolveDeptOptions = (data) =>
  data.reduce((acc, item) => {
    return {
      ...acc,
      [item.departId]: item.departName,
    };
  }, {});

// 回显已上传文件列表用
export const getFakeFileList = (files) => {
  if (Array.isArray(files)) {
    return (
      files?.map((item) => ({
        uid: uuidV4(),
        name: item.name || item.fileName,
        status: 'done',
        url: item.url || item.fileUrl,
        id: item.id,
      })) || []
    );
  } else {
    return [];
  }
};

// 可编辑表格更新列表数据时用
export const formatDigitalColumns = (list, digitKeys) =>
  list.map((item) =>
    Object.keys(item).reduce(
      (acc, k) => ({
        ...acc,
        [k]: digitKeys.includes(k) ? +item[k] : item[k],
      }),
      {},
    ),
  );

export const digitUppercase = (number) => {
  const nzhcn = Nzh.cn;
  if (number)
    return nzhcn.toMoney(number, {outSymbol: false});
  else return;
};

export const fieldMapping = (item, fieldMap) => {
  const _item = item || {};
  return {
    ..._item,
    ...Object.keys(fieldMap).reduce((acc, key) => {
      const targetKey = fieldMap[key];
      return {
        ...acc,
        [targetKey]: _item[key],
      };
    }, {}),
  };
};

// 选择审批流弹窗用
export const getNodeFields = (nodes) =>
  nodes?.map((item) => ({
    type: 'Select',
    name: item.userTaskId,
    label: '审核人：',
    rules: [
      {
        required: true,
      },
    ],
    valueEnum: item.users.reduce(
      (acc, i) => ({
        ...acc,
        [i.userId]: i.realName,
      }),
      {},
    ),
  })) || [];

//过滤数据修改为适用于select得格式 参数data为原始数组，option为返回结果初始值为空数组 label/value为展示字段
export function filterTreeData(data, options = [], label = 'label', value = 'value') {
  data.map((item, index) => {
    options.push({
      [label]: item.subjectCode + ' ' + item.subjectName,
      [value]: item.subjectCode,
    });
    if (item.child || item.children) {
      filterTreeData(item.child || item.children, (options[index].children = []), label, value);
    }
  });
  return options;
}

/**
 * @description: 校验数字长度在 10 位以内，且小数点后最多两位
 * @param {String | Number} input
 * @return {Boolean}
 */
export function isTwoDecimalFloat(input) {
  if (input === '') return true
  const num = +input;
  if (typeof num !== 'number') {
    return false;
  }
  const reg = /^\d{1,10}(\.\d{1,2})?$/g;
  return reg.test(input);
}

export function isTwoDecimalFloatWithoutLength(input) {
  if (input === '') return true
  const num = +input;
  if (typeof num !== 'number') {
    return false;
  }
  const reg = /^\d{1,}(\.\d{1,2})?$/g;
  return reg.test(input);
}

export const compose =
  (...fns) =>
    (arg) =>
      fns.reduce((composed, f) => f(composed), arg);

export const deepSearch = (childDataIndex, keyDataIndex, data, key) => {
  const getChild = (childDataIndex) => _get(_, childDataIndex);
  const isNotEmptyArr = (arr) => arr?.length;

  const found = find(data, (item) => item[keyDataIndex] === key);
  const children = compose(
    _map(_, getChild(childDataIndex)),
    _filter(_, isNotEmptyArr),
    flattenDeep,
  )(data);
  return !found && children.length
    ? deepSearch(childDataIndex, keyDataIndex, children, key)
    : found;
};

export const searchPath = (id, tree, iteratee) => {
  const _search = (acc, item) => {
    if (!acc.found) {
      const newPath = [...acc.path, iteratee(item)];
      if (item.value === id) {
        return {
          found: true,
          path: newPath
        };
      }
      if (item.children.length) {
        const newAcc = item.children.reduce(_search, {
          found: false,
          path: newPath
        });
        return newAcc.found ? newAcc : acc;
      }
    }
    return acc;
  };

  const result = tree.reduce(_search, {path: [], found: false});
  return result.found ? result.path : [];
};

export const calcTotal = (list = [], key) => {
  return list.reduce((acc, item) => {
    return +Number(new Big(acc).plus(+get(item, key, 0) || 0).toString()).toFixed(2);
  }, 0);
};
export const searchFormData = ([values, code, name]) => {
  return {
    label: values[name] ? `${values[name]}/${values[code]}` : '',
    key: values[code],
    value: values[code],
  }
}
export const searchSelectData = (props) => {
  const {values = {}, name = '', code = ''} = props;
  return {
    label: values[name] ? `${values[name]}/${values[code]}` : '',
    key: values[code],
    value: values[code],
  }
}
export const searchSelectDataId = (props) => {
  const {values = {}, name = '', code = '', id = ''} = props;
  return {
    label: values[name] ? `${values[name]}/${values[code]}` : '',
    key: values[id],
    value: values[id],
  }
}
/**
 * 为了适配antd table “当数据中有 children 字段时会自动展示为树形表格” 这一不合理的规则，删除叶子节点的children属性
 * @param cur 节点
 * @returns 新的结点
 */
export const removeEmptyChildrenKey = (cur) => (cur?.children?.length ? cur : omit(cur, 'children'));

export const NumberFixedTo2 = (number) => +Number(number).toFixed(2)

/**
 *  是否为一个可以转换为数字参与计算的值
 * @param value 任意类型的值
 * @returns {Boolean}
 */

export const isNumberValue = (value: any) => !Number.isNaN(+value)

export const isRealNumber = (value) => typeof value === 'number' && !Number.isNaN(value)

/**
 * 判断是否为业务意义上的数字，通常认为类似：'1'、'1.1'、'-1.1'的形式都是数字
 * @param {*} value
 * @returns
 */
export const isNumber = (value) => {
  switch (typeof value) {
    case 'number':
      return isRealNumber(value)
    case 'string':
      return /^-?\d+(\.\d+)?$/g.test(value)
    default:
      return false
  }
}


export function change(limit: number) {
  let size = "";
  if (limit < 0.1 * 1024) {                            //小于0.1KB，则转化成B
    size = limit.toFixed(2) + "B"
  } else if (limit < 0.1 * 1024 * 1024) {            //小于0.1MB，则转化成KB
    size = (limit / 1024).toFixed(2) + "KB"
  } else if (limit <  1024 * 1024 * 1024) {        //小于0.1GB，则转化成MB
    size = (limit / (1024 * 1024)).toFixed(2) + "MB"
  } else {                                            //其他转化成GB
    size = (limit / (1024 * 1024 * 1024)).toFixed(2) + "GB"
  }

  let sizeStr = size + "";                        //转成字符串
  let index = sizeStr.indexOf(".");                    //获取小数点处的索引
  let dou = sizeStr.substr(index + 1, 2)            //获取小数点后两位的值
  if (dou == "00") {                                //判断后两位是否为00，如果是则删除00
    return sizeStr.substring(0, index) + sizeStr.substr(index + 3, 2)
  }
  return size;
}

export function dateFormat(timestamp: string){
  const date = new Date(timestamp);

  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, "0");
  const day = String(date.getDate()).padStart(2, "0");
  const hours = String(date.getHours()).padStart(2, "0");
  const minutes = String(date.getMinutes()).padStart(2, "0");
  const seconds = String(date.getSeconds()).padStart(2, "0");

  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
}
